"""
Grave! Important! Важно!

Proletoj el ĉiuj landoj, unuiĝu!
Workers of the world, unite!
Пролетарии всех стран, соединяйтесь!

https://tkom.pro
"""

from graphene import relay, Field, ObjectType, Float, Int, DateTime, List, UUID, String
from graphene_django import DjangoObjectType
from siriuso.api.filters import SiriusoFilterConnectionField
from siriuso.api.types import SiriusoLingvo
from django.db.models import Sum, functions

from ..models import *


class KontaktoTipoNode(DjangoObjectType):
    search_fields = ('uuid', 'nomo__enhavo__icontains')
    json_filter_fields = {
        'nomo__enhavo': ['contains', 'icontains'],
    }
    nomo = Field(SiriusoLingvo)

    class Meta:
        model = KontaktoTipo
        filter_fields = ['uuid', 'kodo']
        interfaces = (relay.Node,)


class KontaktoNode(DjangoObjectType):
    search_fields = ('uuid', 'valoro__icontains')
    valoro_href = String()

    class Meta:
        model = Kontakto
        fields = ['uuid', 'tipo', 'valoro', 'publikigo']
        filter_fields = {
            'uuid': ['exact'],
            'tipo__kodo': ['exact', 'icontains', 'istartswith', 'iendswith'],
            'valoro': ['exact', 'icontains', 'istartswith', 'iendswith'],
            'forigo': ['exact'],
            'publikigo': ['exact'],
        }
        interfaces = (relay.Node,)

    @staticmethod
    def resolve_valoro_href(root, info, **kwargs):
        if root.tipo.href:
            return root.tipo.href.format(valoro=root.valoro)
        return None


class KombatantoTipoNode(DjangoObjectType):
    search_fields = ('uuid', 'nomo__enhavo__icontains')
    json_filter_fields = {
        'nomo__enhavo': ['contains', 'icontains'],
    }

    nomo = Field(SiriusoLingvo)

    class Meta:
        model = KombatantoTipo
        interfaces = (relay.Node,)
        filter_fields = {
            'kodo': ['exact', 'icontains', 'startswith', 'endswith'],
        }


class KombatantoSpecoNode(DjangoObjectType):
    search_fields = ('uuid', 'nomo__enhavo__icontains')
    json_filter_fields = {
        'nomo__enhavo': ['contains', 'icontains'],
    }

    nomo = Field(SiriusoLingvo)

    class Meta:
        model = KombatantoSpeco
        interfaces = (relay.Node,)
        filter_fields = {
            'kodo': ['exact', 'icontains', 'startswith', 'endswith'],
        }


class KombatantoKategorioNode(DjangoObjectType):
    search_fields = ('uuid', 'nomo__enhavo__icontains')
    json_filter_fields = {
        'nomo__enhavo': ['contains', 'icontains'],
    }

    nomo = Field(SiriusoLingvo)

    class Meta:
        model = KombatantoKategorio
        interfaces = (relay.Node,)
        filter_fields = {
            'uuid': ['exact', 'in'],
            'kodo': ['exact', 'icontains', 'startswith', 'endswith'],
        }


class KombatantoResursoNomenklaturoNode(DjangoObjectType):
    search_fields = ('uuid', )
    json_filter_fields = {
    }

    resto = Field(Float)
    kosto = Field(Float)
    ununura_prezo = Field(Float)
    rezervita = Field(Float)

    class Meta:
        model = KombatantoResursoNomenklaturo
        interfaces = (relay.Node,)
        filter_fields = {
            'uuid': ['exact', 'in', 'not_in', 'ne'],
            'organizo__uuid': ['exact', 'in', 'not_in', 'ne'],
            'organizo__posedanto__uuid': ['exact', 'in', 'ne'],
            'publikigo': ['exact'],
            'forigo': ['exact'],
        }

    @staticmethod
    def resolve_resto(root, info, **kwargs):
        return round(KombatantoResurso.objects.filter(
            organizo=root.organizo,
            # dokumento__publikigo=True,
            # dokumento__forigo=False,
            publikigo=True,
            forigo=False,
            rezervita=False,
            elcherpita=False
        ).aggregate(Sum('kvanto'))['kvanto__sum'], 3)

    @staticmethod
    def resolve_kosto(root, info, **kwargs):
        return round(KombatantoResurso.objects.filter(
            organizo=root.organizo,
            # dokumento__publikigo=True,
            # dokumento__forigo=False,
            rezervita=False,
            publikigo=True,
            forigo=False,
            elcherpita=False
        ).aggregate(Sum('kosto'))['kosto__sum'] or 0, 2)

    @staticmethod
    def resolve_ununura_prezo(root, info, **kwargs):
        kvanto = KombatantoResursoNomenklaturoNode.resolve_resto(root, info, **kwargs)
        kosto = KombatantoResursoNomenklaturoNode.resolve_kosto(root, info, **kwargs)

        if not kosto:
            return 0

        return round(kosto/kvanto, 2)

    @staticmethod
    def resolve_rezervita(root, info, **kwargs):
        # rez = DokumentoKordo.objects.filter(
        #     dokumento__celo_magazeno=root.organizo,
        #     dokumento__rezervita=True,
        #     dokumento__publikigo=True,
        #     dokumento__forigo=False,
        #     publikigo=True,
        #     forigo=False,
        #     resurso=root.resurso
        # ).aggregate(Sum('kvanto'))['kvanto__sum'] or 0

        # rez += KombatantoResurso.objects.filter(
        rez = KombatantoResurso.objects.filter(
            organizo=root.organizo,
            publikigo=True,
            forigo=False,
            rezervita=True
        ).aggregate(Sum('kvanto'))['kvanto__sum'] or 0
        return round(rez, 3)


class KombatantoResursoNode(DjangoObjectType):
    search_fields = ('uuid', )
    json_filter_fields = {
    }

    class Meta:
        model = KombatantoResurso
        interfaces = (relay.Node,)
        filter_fields = {
            'hid': ['exact', 'in', 'not_in', 'ne'],
            'uuid': ['exact', 'in', 'not_in', 'ne'],
            'organizo__uuid': ['exact', 'in', 'not_in', 'ne'],
            'organizo__speco__kodo': ['exact', 'in', 'not_in', 'contains'],
            'organizo__posedanto__speco__kodo': ['exact', 'in', 'not_in', 'contains'],
            'publikigo': ['exact'],
            'forigo': ['exact'],
            'elcherpita': ['exact'],
        }


class KombatantoNode(DjangoObjectType):
    search_fields = ('uuid', 'nomo__enhavo__icontains')
    json_filter_fields = {
        'nomo__enhavo': ['contains', 'icontains'],
    }

    nomo = Field(SiriusoLingvo)
    unua_nomo = Field(SiriusoLingvo)
    dua_nomo = Field(SiriusoLingvo)
    familinomo = Field(SiriusoLingvo)
    informoj = Field(SiriusoLingvo)
    kontaktoj = SiriusoFilterConnectionField(KontaktoNode)

    class Meta:
        model = Kombatanto
        interfaces = (relay.Node,)
        filter_fields = {
            'hid': ['exact', 'in', 'not_in', 'ne'],
            'uuid': ['exact', 'in', 'not_in', 'ne'],
            'tipo__kodo': ['exact', 'icontains', 'startswith', 'endswith', 'ne'],
            'speco__kodo': ['exact', 'icontains', 'startswith', 'endswith', 'ne'],
            'publikigo': ['exact'],
            'forigo': ['exact'],
            'posedanto__uuid': ['exact', 'in'],
        }

    @staticmethod
    def resolve_kontaktoj(root, info, **kwargs):
        return Kontakto.objects.filter(organizo=root)


# Строки статистики
class ResursoStatistikoKordoNode(ObjectType):
    dato = DateTime()
    organizo = Field(KombatantoNode)
    kvanto = Float()
    kosto = Float()

    @staticmethod
    def resolve_organizo(root, info, **kwargs):
        organizo = Kombatanto.objects.none()

        try:
            organizo = Kombatanto.objects.get(uuid=root['resurso_nomenklaturo__organizo__posedanto'])
        except Kombatanto.DoesNotExist:
            pass

        return organizo

    @staticmethod
    def resolve_dato(root, info, **kwargs):
        return root.get('ago_dato')

    @staticmethod
    def resolve_kvanto(root, info, **kwargs):
        return root.get('kvanto')

    @staticmethod
    def resolve_kosto(root, info, **kwargs):
        return root.get('kosto')


# Статистика продажи ресурса
class ResursoStatistikoNode(ObjectType):
    pags = {}
    params = {}

    kordoj = List(ResursoStatistikoKordoNode)
    tuta_kosto = Float()
    tuta_kvanto = Float()

    def __init__(self, first=None, last=None, organizo__uuid=None, komenco_dato=None,
                 fina_dato=None, organizo__uuid__in=None, homo__uuid=None, homo__uuid__in=None,
                 order_by=None, *args, **kwargs):
        self.pags['first'] = first
        self.pags['last'] = last
        self.pags['order_by'] = order_by
        self.params['homo__uuid'] = homo__uuid
        self.params['homo__uuid__in'] = homo__uuid__in
        self.params['homo__organizo__uuid'] = organizo__uuid
        self.params['homo__organizo__uuid__in'] = organizo__uuid__in
        self.params['dato__gte'] = komenco_dato
        self.params['dato__lte'] = fina_dato

        super().__init__(*args, **kwargs)

    def resolve_kordoj(self, info, **kwargs):
        params = {key: val for key, val in self.params.items() if val is not None}

        statistiko = (KombatantoBonusPunkto.objects.filter(publikigo=True, forigo=False, **params)
                      .annotate(ago_dato=functions.TruncDay('dato'))
                      .values('resurso_nomenklaturo__organizo__posedanto', 'ago_dato')
                      .annotate(kvanto=Sum('resurso_nomenklaturo__kvanto'), kosto=Sum('resurso_nomenklaturo__kosto')))

        if 'order_by' in self.pags and self.pags['order_by']:
            statistiko = statistiko.order_by(*self.pags['order_by'])

        return statistiko

    def resolve_tuta_kosto(self, info, **kwargs):
        params = {key: val for key, val in self.params.items() if val is not None}
        kosto = (KombatantoBonusPunkto.objects.filter(publikigo=True, forigo=False, **params)
                 .aggregate(Sum('resurso_nomenklaturo__kosto')))['resurso_nomenklaturo__kosto__sum'] or 0
        return round(kosto, 2)

    def resolve_tuta_kvanto(self, info, **kwargs):
        params = {key: val for key, val in self.params.items() if val is not None}
        kosto = (KombatantoBonusPunkto.objects.filter(publikigo=True, forigo=False, **params)
                 .aggregate(Sum('resurso_nomenklaturo__kvanto')))['resurso_nomenklaturo__kvanto__sum'] or 0
        return round(kosto, 3)


class KombatantoQuery(ObjectType):
    kombatantoj_specoj = SiriusoFilterConnectionField(KombatantoSpecoNode)
    kombatantoj_tipoj = SiriusoFilterConnectionField(KombatantoTipoNode)
    kombatantoj_kategorioj = SiriusoFilterConnectionField(KombatantoKategorioNode)
    kombatantoj = SiriusoFilterConnectionField(KombatantoNode)
    kombatantoj_resursoj_nomenklaturoj = SiriusoFilterConnectionField(KombatantoResursoNomenklaturoNode)
    kombatantoj_resursoj = SiriusoFilterConnectionField(KombatantoResursoNode)
    resurso_statistiko = Field(
        ResursoStatistikoNode,
        first=Int(), last=Int(),
        homo__uuid=UUID(),
        homo__uuid__in=List(UUID),
        organizo__uuid=UUID(),
        organizo__uuid__in=List(UUID),
        komenco_dato=DateTime(),
        fina_dato=DateTime(),
        order_by=List(String)
    )

    @staticmethod
    def resolve_resurso_statistiko(root, info, **kwargs):
        return ResursoStatistikoNode(**kwargs)
